const dateFormat = (date = new Date(), fmt = 'yyyy-MM-dd hh:mm:ss') => {
  let ret
  date = new Date(date)
  const opt = {
    'y+': date.getFullYear().toString(), // 年
    'M+': (date.getMonth() + 1).toString(), // 月
    'd+': date.getDate().toString(), // 日
    'h+': date.getHours().toString(), // 时
    'm+': date.getMinutes().toString(), // 分
    's+': date.getSeconds().toString() // 秒
    // 有其他格式化字符需求可以继续添加，必须转化成字符串
  }
  for (const k in opt) {
    ret = new RegExp('(' + k + ')').exec(fmt)
    if (ret) {
      fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, '0')))
    }
  }
  return fmt
}

class CommonWebSocket {
  constructor (config = {}) {
    const {
      url,
      openFun,
      messageFun,
      closeFun,
      errorFun,
      heart
    } = config
    // 存储的websocket对象
    this.socket = null
    this.url = url
    this.openFun = openFun
    this.messageFun = messageFun
    this.closeFun = closeFun
    this.errorFun = errorFun
    this.heart = heart || ({
      disabled: false,
      timeout: 10000,
      message: () => '{"cmd":2,"time":"' + dateFormat() + '"}'
    })
    // 节流标识
    this.connectFlag = false
    // 关闭标志
    this.closeFlag = true
    const $this = this
    // 心跳机制
    this.heartCheck = {
      timeout: $this.heart.timeout,
      timeoutObj: null,
      serverTimeoutObj: null,
      reset () {
        clearTimeout(this.timeoutObj)
        clearTimeout(this.serverTimeoutObj)
        // console.log('清空定时器', this.timeoutObj, this.serverTimeoutObj, dateFormat())
        return this
      },
      start () {
        this.timeoutObj = setTimeout(() => {
          // 这里发送一个心跳，后端收到后，同样返回一个心跳消息，
          // onmessage拿到返回的心跳就说明连接正常
          // console.log('ping >>>', $this.heart.message())
          $this.send($this.heart.message())
          this.serverTimeoutObj = setTimeout(() => {
            // 如果超过一定时间还没重置，说明后端主动断开了
            // console.log('主动断开')
            $this.socket.close()
          }, this.timeout)
          // console.log('超时定时器', this.serverTimeoutObj, this, dateFormat())
        }, this.timeout)
        // console.log('定时器', this.timeoutObj, this, dateFormat())
      }
    }
    this.createWebsocket()
  }

  // 建立websocket连接函数
  createWebsocket () {
    // console.log('创建socket', this.url)
    this.socket = new WebSocket(this.url)
    this.init()
  }

  // 关闭websocket
  closeWebsocket () {
    this.heartCheck.reset()
    this.socket && this.socket.close()
    this.closeFlag = false
  }

  // 对WebSocket各种事件进行监听
  init () {
    this.socket.onopen = () => {
      // console.log('Websocket连接成功', dateFormat())
      // 连接已经打开
      this.openFun && this.openFun()
      // 重置心跳机制
      this.heart.disabled || this.heartCheck.reset().start()
    }
    this.socket.onmessage = (event) => {
      const msg = JSON.parse(event.data)
      // console.log('收到消息', msg)
      if (msg.cmd === 2) {
        // console.log('pong <<<', '心跳消息')
      } else {
        this.messageFun && this.messageFun(msg)
      }
      // 收到消息表示连接正常，所以重置心跳机制
      !this.heart.disabled && this.heartCheck.reset().start()
    }
    this.socket.onclose = (event) => {
      // console.log('Websocket关闭', event)
      // 关闭心跳
      this.heart.disabled || this.heartCheck.reset()
      this.closeFun && this.closeFun()
      this.closeFlag && this.reConnect()
    }
    this.socket.onerror = (event) => {
      // console.log('Websocket报错', event)
      // 报错+重连
      this.heart.disabled || this.heartCheck.reset()
      this.errorFun && this.errorFun()
      this.closeFlag && this.reConnect()
    }
  }

  // 重连函数
  // 因为重连函数会被socket事件频繁触发，所以通过函数节流限制重连请求发送
  reConnect () {
    if (this.flag) {
      return
    }
    this.flag = true
    setTimeout(() => {
      this.createWebsocket()
      this.flag = false
    }, 3000)
  }

  // 发送消息
  send (message) {
    this.socket.send(message)
  }
}

export default CommonWebSocket
